package com.lemon.springcloud.core.component.zookeeper;

import com.lemon.springcloud.core.initial.LemonApplicationInitializer;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * Class Name: ZkPropListener
 * Create Date: 6/20/18 10:53 AM
 * Creator: lemon
 * Version: v1.0
 * Updater:
 * Date Time:
 * Description:
 * <p>
 * 实现监听 zookeeper 上 properties 文件的变更，并通知到继承了当前类
 */
public abstract class ZkPropKeyListener {

    private static final Logger LOGGER = LogManager.getLogger(ZkPropKeyListener.class);

    private Map<String, Field> keyFieldMapping = new HashMap<>();

    /**
     * 所有实现了该类的配置类
     */
    public ZkPropKeyListener() {
        Class<?> aClass = this.getClass().getSuperclass();
        Field[] declaredFields = aClass.getDeclaredFields();

        for (Field declaredField : declaredFields) {

            Value valueAnnotation = declaredField.getDeclaredAnnotation(Value.class);
            if (valueAnnotation == null) {
                continue;
            }

            String key = valueAnnotation.value();
            key = key.replace("${", "").replace("}", "");
            LemonApplicationInitializer.addZkPropertyListener(key, this);
            keyFieldMapping.put(key, declaredField);
        }

    }

    /**
     * 当配置类的相关文件配置变更后，会刷新到当前子类的值中
     *
     * @param prop 变更的配置内容
     */
    @SuppressWarnings("SuspiciousMethodCalls")
    public void onPropChanged(Properties prop) {

        for (Object key : prop.keySet()) {
            Field field = keyFieldMapping.get(key);
            if (field != null) {
                String keyInfo = this.getClass().getSuperclass().getName() + ".${" + key + "}";
                LOGGER.info("MOP-LOGGER - On Key Property [" + keyInfo + "] changed [" + prop.get(key) + "].");
                try {
                    if (field.isAccessible()) {
                        field.set(this, prop.get(key));
                    } else {
                        field.setAccessible(true);
                        field.set(this, prop.get(key));
                        field.setAccessible(false);
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

    }

}
